#include "channel.h"
#include "event_loop.h"

using namespace el;

Channel::Channel(EventLoop * loop, FD fd)
	:loop_(loop),
	fd_(fd),
	event_(NONE_EVENT),
	revent_(NONE_EVENT),
	added_to_loop_(false),
	porcessing_event_(false)
{
}

Channel::~Channel()
{
	assert(!added_to_loop_);
	assert(!porcessing_event_);
}

void el::Channel::release()
{
	if (!loop_->isInLoopThread())
	{
		loop_->queueInLoop(Functor(this, &Channel::release));
	}
	else
	{
		delete this;
	}
}

int el::Channel::getEvent()
{
	assert(loop_->isInLoopThread());
	return event_;
}

void Channel::setREvent(int revent)
{
	assert(loop_->isInLoopThread());
	revent_ = revent;
}

bool el::Channel::enableReadEvent()
{
	event_ |= READ_EVENT;
	return update();
}

void el::Channel::disableReadEvent()
{
	event_ &= ~READ_EVENT;
	update();
}

bool el::Channel::enableWriteEvent()
{
	event_ |= WRITE_EVENT;
	return update();
}

void el::Channel::disableWriteEvent()
{
	event_ &= ~WRITE_EVENT;
	update();
}

bool el::Channel::enableExecptionEvent()
{
	event_ |= EXCEPTION_EVENT;
	return update();
}

void el::Channel::disableExecptionEvent()
{
	event_ &= ~EXCEPTION_EVENT;
	update();
}

bool el::Channel::enableAllEvent()
{
	event_ |= READ_EVENT;
	event_ |= WRITE_EVENT;
	event_ |= EXCEPTION_EVENT;
	return update();
}

void el::Channel::disableAllEvent()
{
	event_ = NONE_EVENT;
	update();
}

void el::Channel::setReadCallBack(const Functor & functor)
{
	read_callback_ = functor;
}

void el::Channel::setWriteCallBack(const Functor & functor)
{
	write_callback_ = functor;
}

void el::Channel::setExceptionCallBack(const Functor & functor)
{
	exception_callback_ = functor;
}

bool Channel::noneEvent()
{
	assert(loop_->isInLoopThread());
	return NONE_EVENT == event_;
}

bool el::Channel::hasReadEvent()
{
	assert(loop_->isInLoopThread());
	return (READ_EVENT & event_) != 0;
}

bool el::Channel::hasWriteEvent()
{
	assert(loop_->isInLoopThread());
	return (WRITE_EVENT & event_) != 0;
}

bool el::Channel::hasExceptionEvent()
{
	assert(loop_->isInLoopThread());
	return (EXCEPTION_EVENT & event_) != 0;
}

EventLoop* Channel::ownerLoop()
{
	return loop_;
}

Channel::FD Channel::fd()
{
	return fd_;
}

void Channel::handleEvent()
{
	porcessing_event_ = true;
	if (READ_EVENT & revent_)
	{
		read_callback_();
	}
	if (WRITE_EVENT & revent_)
	{
		write_callback_();
	}
	if (EXCEPTION_EVENT & revent_)
	{
		exception_callback_();
	}
	revent_ = NONE_EVENT;
	porcessing_event_ = false;
}

void el::Channel::remove()
{
	if (!added_to_loop_)
	{
		return;
	}
	assert(noneEvent());
	added_to_loop_ = false;
	loop_->removeChannel(this);
}

bool el::Channel::update()
{
	added_to_loop_ = true;
	if (!loop_->updateChannel(this))
	{
		added_to_loop_ = false;
		return false;
	}
	else
	{
		return true;
	}
}
